package common

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"syscall"

	"github.com/BurntSushi/toml"
	log "github.com/sirupsen/logrus"
)

var (
	RunDir          string
	LogDir          string
	AgentConfigPath string
	DefaultFlag     func()
)

func GetRunDir() string {
	return RunDir
}

func GetLogDir() string {
	return LogDir
}

var AgentConfig = struct {
	// Agent 迭代一段时间后，可能会部署多种版本
	// 那么 Agent 要写清楚支持版本里的功能有哪写
	// supported_version 即是一个整体的功能版本描述
	// version 1.0.0 => 100_000_000, major=100, minor=000, patch=000
	SupportedVersion int    `toml:"supported_version" json:"supported_version,omitempty"`
	EnableTLS        bool   `toml:"EnableTLS" json:"EnableTLS,omitempty"`
	Debug            bool   `toml:"debug" json:"debug,omitempty"`
	Environment      string `toml:"environment" json:"environment,omitempty"`
	OpenTask         bool   `toml:"openTask" json:"openTask,omitempty"`
	TaskSecond       int    `toml:"taskSecond" json:"taskSecond,omitempty"`
	SyncType         string `toml:"syncType" json:"syncType,omitempty"`
	LogDir           string `toml:"logDir" json:"logDir,omitempty"`

	// rpc
	Rpc rpc `toml:"rpc" json:"rpc,omitempty"`

	// http
	Http http `toml:"http" json:"http,omitempty"`

	// Mysql
	Mysql mysql `toml:"mysql" json:"mysql,omitempty"`

	// GcRdsHa
	GcRdsHa gcrdsha `toml:"gcrdsha" json:"gcrdsha,omitempty"`

	// Orch
	Orch orch `toml:"orch" json:"orch,omitempty"`

	// ProxySql
	ProxySql proxySql `toml:"proxySql" json:"proxySql,omitempty"`

	// Sentinel
	Sentinel Sentinel `toml:"Sentinel" json:"Sentinel,omitempty"`

	// vip
	Vip vip `toml:"vip" json:"vip,omitempty"`
}{}

type vip struct {
	Url string `toml:"url" json:"url,omitempty"`
}

type Sentinel struct {
	Nodes            string `toml:"nodes" json:"nodes,omitempty"`
	RdsMysqlUser     string `toml:"rdsMysqlUser" json:"rdsMysqlUser,omitempty"`
	RdsMysqlPwd      string `toml:"rdsMysqlPwd" json:"rdsMysqlPwd,omitempty"`
	RdsReplMysqlUser string `toml:"rdsReplMysqlUser" json:"rdsReplMysqlUser,omitempty"`
	RdsReplMysqlPwd  string `toml:"rdsReplMysqlPwd" json:"rdsReplMysqlPwd,omitempty"`
	Concurrency      uint32 `toml:"concurrency" json:"concurrency,omitempty"`
	Timeout          uint32 `toml:"timeout" json:"timeout,omitempty"`
}

type rpc struct {
	Enable bool   `toml:"enable" json:"enable,omitempty"`
	Listen string `toml:"listen" json:"listen,omitempty"`
	Port   int    `toml:"port" json:"port,omitempty"`
}

type orch struct {
	Url string `toml:"url" json:"url,omitempty"`
}

type http struct {
	Port int `toml:"port" json:"port,omitempty"`
}

type mysql struct {
	User   string `toml:"user" json:"user,omitempty"`
	Pwd    string `toml:"pwd" json:"pwd,omitempty"`
	Ip     string `toml:"ip" json:"ip,omitempty"`
	Port   int    `toml:"port" json:"port,omitempty"`
	DbName string `toml:"dbName" json:"dbName,omitempty"`
}

type proxySql struct {
	Open bool   `toml:"open" json:"open,omitempty"`
	User string `toml:"user" json:"user,omitempty"`
	Pwd  string `toml:"pwd" json:"pwd,omitempty"`
	Ip   string `toml:"ip" json:"ip,omitempty"`
	Port int    `toml:"port" json:"port,omitempty"`
}

type gcrdsha struct {
	ServerPem  string `toml:"serverPem" json:"serverPem,omitempty"`
	ServerKey  string `toml:"serverKey" json:"serverKey,omitempty"`
	ClientPem  string `toml:"clientPem" json:"clientPem,omitempty"`
	ClientKey  string `toml:"ClientKey" json:"ClientKey,omitempty"`
	Crt        string `toml:"crt" json:"crt,omitempty"`
	CommonName string `toml:"commonName" json:"commonName,omitempty"`
}

// RedirectOutput redirectOutput 重定向stdout,stderr 到日志文件
func RedirectOutput() {
	reader, writer, err := os.Pipe()
	if err != nil {
		log.Fatal(err)
	}
	// 为什么不用os.Stdout = writer 呢？
	// 参考这个issue：https://github.com/golang/go/issues/325#issuecomment-66049178
	_ = syscall.Dup2(int(writer.Fd()), 1)
	_ = syscall.Dup2(int(writer.Fd()), 2)
	scanner := bufio.NewScanner(reader)
	for scanner.Scan() {
		log.WithField("from", "stdout").Info(scanner.Text())
	}
}

func init() {
	flag.StringVar(&AgentConfigPath, "conf", fmt.Sprintf("../../configs/agent-%s.toml", GetEnvironment()), "Agent config path")
	if _, err := os.Stat(AgentConfigPath); err != nil {
		log.Fatalf("Wrong AgentConfigPath: %s", AgentConfigPath)
	}
	_, err := toml.DecodeFile(AgentConfigPath, &AgentConfig)
	if err != nil {
		log.Fatalf("Decode agent config failed! path: %v, err: %v", AgentConfigPath, err)
	}
	go func() {
		if IsDevelop() {
			conf, _ := json.Marshal(AgentConfig)
			log.Printf("配置信息：%+v\r\n", string(conf))
			log.Println("配置文件路径：", AgentConfigPath)
		}
	}()
	flag.StringVar(&RunDir, "run_path", "/tmp", "running directory")
	flag.StringVar(&LogDir, "log_path", AgentConfig.LogDir, "log file directory")
	if IsOnline() {
		flag.Parse()
	}
	DefaultFlag = flag.Usage
	flag.Usage = commandHelp

}

func commandHelp() {
	//DefaultFlag()
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  -conf: 默认配置文件路径， 默认：gc-rds-ha/configs/agent.toml\n")
	fmt.Fprintf(os.Stderr, "  -run_path: 程序运行目录，默认：/tmp\n")
	fmt.Fprintf(os.Stderr, "  -log_path: 日志输出路径，默认：/tmp\n")
	fmt.Fprintf(flag.CommandLine.Output(), "\n 当前版本: %d\n", AgentConfig.SupportedVersion)
}
